<?php

/*
 * PrototypeObject
 * 
 * Use lambda functions in 5.3.0!
 * Prototype::Extend( function() { } )
 */
class Prototype {
	public static $prototypes = array();

	/*
	 * As of 5.3.0, update this to accept 1 or 2 params, and if 1 param
	 * passed in, that will be the extension class name, and the parent
	 * class name will be used for the first var. <3 late static binding && closures!
	 * @param $class class to extend
	 * @param $extension_class class to extend the first class with
	 */
	public static function Extend() {
		$args = func_get_args();
		if(version_compare(phpversion(), '5.3.0', '>=')) {
			//if()
		}

		list($class, $extension_class) = $args;

		$rf = new ReflectionClass($extension_class);
		$methods = array();

		self::$prototypes[$class] = array();

		foreach ($rf->getMethods() as $method) {
			if ($method->isPublic() && $method->isStatic() && substr($method->getName(), 0, 2) != '__') {
				self::$prototypes[$class][$method->getName()] = $extension_class;
			}
		}
	}

	public static function HasPrototype($caller, $method) {
		return isset(self::$prototypes[get_class($caller)][$method]);
	}

	public function __call($method, $args) {
		Prototype::CallPrototype($this, $method, $args);
		
	}

	public static function CallPrototype($caller, $method, $args = null) {
		$class = get_class($caller);

		if (isset(self::$prototypes[$class][$method])) {
			if (!is_array($args)) $args = array();
			array_unshift($args, $caller);

			try {
				$retval = @call_user_func_array(array(self::$prototypes[$class][$method], $method), $args);
				return $retval;
			} catch(Exception $ex) {
				throw $ex;
			}
		}
	}
}
